package com.kaifamiao.month04.day29;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.file.NoSuchFileException;
import java.util.*;

public class ClassUtil {

    //  设计一个方法获取类对象的所有属性
    public static Collection<Field> getAllFields(Class<?> cla) {
        checkClass(cla);
        Field[] fs = cla.getDeclaredFields();
        List<Field> fields = new ArrayList<>(Arrays.asList(fs));
        while ((cla = cla.getSuperclass()) != null) {
            Field[] fss = cla.getDeclaredFields();
            for (Field f : fss) { // 去除private修饰的属性
                if (!Modifier.isPrivate(f.getModifiers())) {
                    fields.add(f);
                }
            }
        }
        return fields;
    }

    // 检验class对象是否合法
    private static void checkClass(Class<?> c) {
        if (c == null) {
            throw new NullPointerException("null Class 对象");
        }
    }

    // 设计一个方法获取类对象的所有的方法
    public static Collection<Method> getAllMethods(Class<?> cla) {
        checkClass(cla);
        Method[] methods = cla.getDeclaredMethods();
        Collection<Method> methodList = new HashSet<>(Arrays.asList(methods));
        while (!(cla = cla.getSuperclass()).equals(Object.class)) {
            Method[] superMethods = cla.getDeclaredMethods();
            for (Method f : superMethods) { // 去除private修饰的方法
                if (!Modifier.isPrivate(f.getModifiers())) {
                    if (isOverride(methodList, f)) {
                        methodList.add(f);
                    }
                }
            }
        }
        return methodList;
    }

    /**
     * 判断方法是否重写
     * @param collection 已有的方法集合
     * @param method     需要判断的方法
     * @return true 方法是重写  false 方法不是重写
     */
    private static boolean isOverride(Collection<Method> collection, Method method) {
        out:
        for (Method m : collection) {
            if (m.getName().equals(method.getName())) { // 方法名一样
                if (m.getParameterCount() == method.getParameterCount()) { // 方法的参数个数一样
                    Class<?>[] ms = m.getParameterTypes();
                    Class<?>[] ms1 = method.getParameterTypes();
                    int i = 0;
                    for (; i < ms.length; i++) {
                        if (ms[i] != ms1[i]) {
                            continue out;
                        }
                    }
                    if (i == ms.length) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 获取指定包下所有的类
     *
     * @param packagePath 包名 eg: com.kaifamiao.demo
     * @return 包下所有类的集合
     */
    public static Collection<Class<?>> getAllClasses(String packagePath) throws NoSuchFileException, ClassNotFoundException {
        String path = packagePath;

        if (packagePath == null || packagePath.length() == 0) {
            throw new NoSuchElementException();
        }
        path = path.replace(".", "\\");
        File file = new File("src", path);
        if (!file.exists() || !file.isDirectory()) {
            throw new NoSuchFileException("文件找不到");
        }
        FileFilter fileFilter = (f) -> f.isFile() && f.getName().endsWith(".java") || f.isDirectory();
        File[] files = file.listFiles(fileFilter);
        if (files == null || files.length == 0) return null;
        ArrayList<File> list = new ArrayList<>(Arrays.asList(files));
        for (int i = 0; i < list.size(); i++) {
            File f = list.get(i);
            if (f.isDirectory()) {
                File[] fs = f.listFiles(fileFilter);
                list.remove(i);
                if (fs != null) {
                    list.addAll(Arrays.asList(fs));
                }
                i--;
            }
        }
        // 存储所有的class对象
        Collection<Class<?>> classList = new ArrayList<>();
        for (File f : list) {
            String name = f.getAbsolutePath().replace("\\", ".");
            // 去除 .java 后缀
            name = name.substring(name.indexOf("src") + 4, name.lastIndexOf('.'));
            // 判断是否含有内部类、匿名类
            String n = name.substring(name.lastIndexOf('.') + 1);
            if (n.length() != name.length()) { // 含有内部类或者匿名类
                if (Character.isDigit(n.charAt(0))) { // 是匿名类
                    continue;
                }
            }
            classList.add(Class.forName(name));
        }
        return classList;
    }

    public static void main(String[] args) throws NoSuchFileException, ClassNotFoundException {
        Class<ArrayList> c = ArrayList.class;
        Collection<Field> cs = getAllFields(c);
        for (Field cs1 : cs) {
            System.out.println(cs1);
        }
        System.out.println("=====我是分割线=====");
        Collection<Method> ms = getAllMethods(c);
        for (Method ms1 : ms) {
            System.out.println(ms1);
        }
        System.out.println("=====我是分割线=====");
        String str = "com.kaifamiao.month04.day07";
        Collection<Class<?>> cList = getAllClasses(str);
        if (cList != null) {
            for (Class<?> cl : cList) {
                System.out.println(cl);
            }
        }
    }
}
